package com.stone.framework.batch.endpoint;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.launch.JobExecutionNotRunningException;
import org.springframework.batch.core.launch.JobInstanceAlreadyExistsException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import com.stone.framework.core.exception.BusinessException;
import com.stone.framework.message.ReqMessage;
import com.stone.framework.message.ResMessage;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@Api(tags = "作业相关")
@RequestMapping("/job")
public abstract class AbstractJobController {
    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private JobRegistry jobRegistry;

    /*@Autowired
    private JobRepository jobRepository;*/

    @Autowired
    private JobOperator jobOperator;

    @ApiOperation(value = "同步启动job", httpMethod = "POST")
    @PostMapping(value = "/start/sync/{jobId}")
    public ResMessage<Void> startSync(@ApiParam(value = "jobId", required = true) @PathVariable("jobId") String jobId,
        @RequestBody ReqMessage<Map<String, String>> reqMessage) {
        JobParameters jobParameters = this.buildJobParameters(reqMessage.getBody());
        try {
            JobExecution jobExecution = jobLauncher.run(jobRegistry.getJob(jobId), jobParameters);
            if (!BatchStatus.COMPLETED.equals(jobExecution.getStatus())) {
                throw new BusinessException("跑批失败");
            }
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
            | JobParametersInvalidException | NoSuchJobException e) {
            throw new BusinessException(e.getMessage());
        }
        return ResMessage.success();
    }

    /*  @ApiOperation(value = "启动job", httpMethod = "POST")
    @PostMapping(value = "/start1/{jobId}")
    public ResMessage<Void> startAsync1(@ApiParam(value = "jobId", required = true) @PathVariable("jobId") String jobId,
        @RequestBody ReqMessage<Map<String, String>> reqMessage) {
        JobParameters jobParameters = this.buildJobParameters(reqMessage.getBody());
        try {
            SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
            jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor("stone-batch-job-"));
            jobLauncher.setJobRepository(jobRepository);
    
            jobLauncher.run(jobRegistry.getJob(jobId), jobParameters);
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
            | JobParametersInvalidException | NoSuchJobException e) {
            throw new BusinessException(e.getMessage());
        }
        return ResMessage.success();
    }*/

    @ApiOperation(value = "启动job", httpMethod = "POST")
    @PostMapping(value = "/start/{jobId}")
    public ResMessage<Void> start(@ApiParam(value = "jobId", required = true) @PathVariable("jobId") String jobId,
        @RequestBody ReqMessage<Map<String, String>> reqMessage) {
        try {
            jobOperator.start(jobId, this.convert(this.buildJobParameters(reqMessage.getBody())));
        } catch (NoSuchJobException | JobInstanceAlreadyExistsException | JobParametersInvalidException e) {
            throw new BusinessException(e.getMessage());
        }
        return ResMessage.success();
    }

    @ApiOperation(value = "停止job", httpMethod = "POST")
    @PostMapping(value = "/stop")
    public ResMessage<Void> stop(@RequestBody ReqMessage<Long> reqMessage) {
        try {
            jobOperator.stop(reqMessage.getBody());
        } catch (NoSuchJobExecutionException | JobExecutionNotRunningException e) {
            throw new BusinessException(e.getMessage());
        }
        return ResMessage.success();
    }

    @ApiOperation(value = "重启job", httpMethod = "POST")
    @PostMapping(value = "/restart")
    public ResMessage<Void> restart(@RequestBody ReqMessage<Long> reqMessage) {
        try {
            jobOperator.restart(reqMessage.getBody());
        } catch (JobInstanceAlreadyCompleteException | NoSuchJobExecutionException | NoSuchJobException
            | JobRestartException | JobParametersInvalidException e) {
            throw new BusinessException(e.getMessage());
        }
        return ResMessage.success();
    }

    protected JobParameters buildJobParameters(Map<String, String> params) {
        String bankCode = params.getOrDefault("bankCode", "0305");
        String instCode = params.getOrDefault("instCode", "0305");
        String path = params.getOrDefault("path", "/ARMC/ext");
        String flag = params.getOrDefault("x", "0");
        long offset = Long.parseLong(params.getOrDefault("offset", "0"));
        String secretId = params.get("secretId");

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate jobDay =
            LocalDate.parse(params.getOrDefault("jobDay", LocalDate.now().minusDays(1L).format(formatter)), formatter);
        jobDay = jobDay.plusDays(offset);

        return new JobParametersBuilder().addString("bankCode", bankCode).addString("instCode", instCode)
            .addString("path", path).addString("jobDay", jobDay.format(formatter)).addString("x", flag)
            .addString("secretId", secretId).toJobParameters();
    }

    private String convert(JobParameters jobParameters) {
        return jobParameters.getParameters().entrySet().stream()
            .map(entry -> entry.getKey().concat("=").concat(String.valueOf(entry.getValue().getValue())))
            .collect(Collectors.joining(","));
    }

}
